package com.czk.netty.nio.chat.practice;

import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;

/**
 * nio群聊系统的服务器
 *
 * @Author:ChenZhangKun
 * @Date: 2021/4/8 15:24
 */
public class NioGroupChantServer {
    /**
     * 选择器
     */
    private Selector selector;
    /**
     * 端口
     */
    private final int PORT=8080;
    /**
     * 通道
     */
    private ServerSocketChannel serverSocketChannel;

    public NioGroupChantServer() throws IOException {
        this.selector = Selector.open();
        this.serverSocketChannel = ServerSocketChannel.open();
        // 绑定端口
        serverSocketChannel.bind(new InetSocketAddress(PORT));
        // 配置非阻塞
        serverSocketChannel.configureBlocking(false);
        // 注册通道
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }
    public void listen() throws IOException {
        while (true){
            // 监听
            int select = selector.select();
            // 有连接时会大于0
            if (select>0){
                // 拿到selectKey
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                // 拿到迭代器
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                // 迭代
                while (iterator.hasNext()){
                    // 拿到具体事例
                    SelectionKey selectionKey = iterator.next();
                    // 拿到状态
                    if (selectionKey.isAcceptable()){
                        // 可连接
                        // 拿到通道
                        SocketChannel channel =  serverSocketChannel.accept();
                        // 配置非阻塞
                        channel.configureBlocking(false);
                        // z注册到选择器
                        channel.register(selector,SelectionKey.OP_READ);
                        // 输出信息
                        System.out.println(channel.getRemoteAddress()+"上线了,大家欢迎");
                    }
                    // 有可读的资源
                    if (selectionKey.isReadable()){
                        System.out.println("服务客户端信息");
                        readMessage(selectionKey);
                    }
                    // 移除
                    iterator.remove();
                }
            }
        }

    }

    private void readMessage(SelectionKey selectionKey) throws IOException {
        // 拿到通道
        SocketChannel socketChannel=(SocketChannel) selectionKey.channel();
        // 创建缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        // 读取数据
        int read = socketChannel.read(byteBuffer);
        // 没到头
        if (read!=-1){
            // 拿到数据
            String message=new String(byteBuffer.array());
            // 输出
            System.out.println(socketChannel.getRemoteAddress()+"说："+message);
            // 转发到其他链接
            transferToOtherClient(socketChannel,message);
        }
    }

    private void transferToOtherClient(SocketChannel socketChannel, String message) throws IOException {
        //
        System.out.println("服务器转发消息中");
        // 拿到所有连接
        Set<SelectionKey> selectionKeys = selector.keys();
        // 遍历
        for (SelectionKey key : selectionKeys) {
            // 拿到通道
            Channel channel = key.channel();
            if (channel instanceof SocketChannel&&Objects.equals(channel,socketChannel)){
                continue;
            }
            // 将buffer数据写入通道
            // 去除服务器
            if (channel instanceof ServerSocketChannel){
                continue;
            }
            SocketChannel socketChannel1=(SocketChannel)channel;
            socketChannel1.write(ByteBuffer.wrap(message.getBytes()));
        }
    }

    public static void main(String[] args) throws IOException {
        NioGroupChantServer server=new NioGroupChantServer();
        server.listen();
    }
}
